structure Main : sig val main : string * string list -> OS.Process.status end =
struct 
  structure TigerLrVals = TigerLrValsFun(structure Token = LrParser.Token)

  structure TigerLex = TigerLexFun(structure Tokens = TigerLrVals.Tokens)

  structure TigerParser = Join(structure ParserData = TigerLrVals.ParserData
                               structure Lex = TigerLex
			       structure LrParser = LrParser)


  fun parse filename =
      let val _ = ( ErrorMsg.reset()
		  ; ErrorMsg.fileName := filename)
	  val file = TextIO.openIn filename
	  fun get _ = TextIO.input file
	  fun parseError(s,p1,p2) = ErrorMsg.error p1 s
	  val lexer = LrParser.Stream.streamify (TigerLex.makeLexer get)
	  val (absyn, _) = TigerParser.parse(30,lexer,parseError,())
      in ( TextIO.closeIn file
	 ; absyn )
      end handle LrParser.ParseError => raise ErrorMsg.Error;

  fun check absyn = ( FindEscape.findEscape absyn
		    ; let val fs = Semant.transProg absyn
		      in
			  if !ErrorMsg.anyErrors then ( TextIO.output (TextIO.stdErr, "type-checking failed, ")
						      ; raise ErrorMsg.Error )
			else fs
		      end )
		    
  fun process p fs = let fun pr f = ( TextIO.output (TextIO.stdErr, f)
				    ; TextIO.output (TextIO.stdErr, "\n")
				    ; (p f
				       handle ErrorMsg.Error => TextIO.output (TextIO.stdErr, "continuing to next file\n"))
				    ; OS.Process.success )
		     in let fun loop [] = OS.Process.success
			      | loop [f] = pr f
			      | loop (f::fs) = ( pr f
					       ; loop fs )
			in loop fs
			end
		     end;

  fun main (_, ("-a" ::  fs)) = process (fn f => let val absyn = parse f
						 in ( check absyn
						    ; PrintAbsyn.print (TextIO.stdOut, absyn) )
						 end)
					fs
    | main (_, ("-u" ::  fs)) = process (fn f => let val absyn = parse f
						 in ( check absyn
						    ; UnparseAbsyn.print (TextIO.stdOut, absyn) )
						 end)
					fs
    | main (_, ("-t" :: fs)) = process (fn f => app (fn MipsFrame.STRING (l, s) => TextIO.output (TextIO.stdOut, ("STRING " ^ (Symbol.name l) ^ ":" ^ (String.toString s) ^ "\n"))
						      | MipsFrame.PROC {body,frame={name,formals,sp}} => ( TextIO.output (TextIO.stdOut, ("PROC " ^ (Symbol.name name) ^ ":\n"))
													 ; Printtree.printtree (TextIO.stdOut, body) ))
						    (check (parse f)))
				       fs
    | main (_, ("-i" :: fs)) = process (fn f => app (fn MipsFrame.STRING (l, s) => TextIO.output (TextIO.stdOut, ("STRING " ^ (Symbol.name l) ^ ":" ^ (String.toString s) ^ "\n"))
						      | MipsFrame.PROC {body,frame={name,formals,sp}} => ( TextIO.output (TextIO.stdOut, ("PROC " ^ (Symbol.name name) ^ ":\n"))
													 ; UnparseTree.printTree (TextIO.stdOut, body) ))
						    (check (parse f)))
				       fs
    | main (_, (c ::  fs)) = ( print ("unrecognized command: " ^ c ^ "\n")
				  ; print "usage: -aitu <filenames>\n"
				  ; OS.Process.failure )
    | main (_, _) = ( print "usage: -atu <filenames>\n"
		    ; OS.Process.failure )
end
